#ifndef FILETRANSFER_H_
#define FILETRANSFER_H_

// system
#include <boost/filesystem.hpp>
#include <iostream>
#include <fstream>

// omnibus
#include "ariba/ariba.h"
#include "Userdatabase.h"
#include "Transport.h"
#include "FileInfo.h"
#include "SystemEvents/Filetransfer/ResumeTransferEvent.h"

// interfaces
#include "interfaces/Useroutputinterface.h"
#include "interfaces/MessageHandlerInterface.h"
#include "interfaces/ConnStatInterface.h"
#include "interfaces/DataReceiverInterface.h"
#include "interfaces/TransferBundleInterface.h"

// messages
#include "messages/TransportMessage.h"


using namespace std;

typedef std::map<string, FilePtr> FileMap;
typedef std::list<FilePtr> FileList;
typedef std::map<string, TransferBundlePtr> TransferBundleMap;

class Filetransfer : public MessageHandlerInterface, ConnStatInterface, DataReceiverInterface
{
public:

  typedef enum _NegSubtypes
  {
    UNDEFINED = 0,
    ACCEPT,
    DECLINE,
    ABORT,
    PUSH_REQUEST,
    CUSTODY_REQUEST,
    PAUSE_NOTIFICATION,
    DEMAND_PAUSE,
    RESUME_REQUEST,
    RESUME,
    DEMAND_RESUME,
    FINISHED,
    FINISHED_ACK,
    LOOK,
    LOOK_REPLY,
    PULL_REQUEST,
    PULL_ACCEPT,
    BUNDLE_INFO,
    BUGS
  } NegotionSubtypes;

  typedef enum _PaySubtypes
  {
      PAY_UNDEFINED = 0,
      DATA,
      ACK
  } PayloadSubtypes;


  Filetransfer();
  Filetransfer(Userdatabase* users, Transport* trans);
  virtual ~Filetransfer();

  // MessageHandlerInterface
  virtual void handleMessage(TransportMessage* msg, TransportMessage::MESSAGE_TYPE type, uint8_t subtype, UserPtr user);

  // DataReceiverInterface
  virtual void data_receive_callback(UserPtr user, PayloadPtr pay);

  void push_file(UserPtr dest, string path);
  void accept_file(string key);
  void accept_file(FilePtr file, string path);
  void decline_file(string key);
  void abort_transfer(string key);
  void pause_transfer(string key, bool just_hold);
  void demand_pause(string key);
  void demand_pause(FilePtr file, bool just_hold);
  void resume_transfer(string key);
  void resume_transfer(FilePtr file, bool just_hold);
  void demand_resume(string key);
  void open_file(string key);
  void open_incoming_dir();
  void look(UserPtr user, string dir);
  void pull_file(UserPtr user, string path);
  void upload_to_server(UserPtr server, UserPtr receiver, string path);

  void status();
//  void status_old();  // XXX DEPRECATED
  void bug_reproduce(UserPtr user);
  void got_bugs(TransportMessage* msg, UserPtr user);

  virtual void got_connection_update(UserPtr user, bool connected);
  void hold_transfers_for(UserPtr user);
  void pause_all_transfers(bool just_hold);
  void connect_partners();

  void save(ptree &pt);
  void load(ptree &pt);

  bool register_bundle(TransferBundlePtr bundle);
  bool bundle_announce_files_waiting(TransferBundlePtr bundle);

private:
  /** handler for incoming packets **/
  /* receiver */
  void got_payload(TransportMessage* msg, UserPtr user);
  void got_pause_notification(TransportMessage* msg, UserPtr user);
  void got_resume_request(TransportMessage* msg, UserPtr user);

  /* sender */
  void got_payload_ack(TransportMessage* msg, UserPtr user);

  void got_push_request(TransportMessage* msg, UserPtr user);
  void got_custody_request(TransportMessage* msg, UserPtr user);

  void got_accept(TransportMessage* msg, UserPtr user);
  void got_pull_request(TransportMessage* msg, UserPtr user);
  void got_pause_demand(TransportMessage* msg, UserPtr user);
  void got_resume_demand(TransportMessage* msg, UserPtr user);

  void got_bundle_info(TransportMessage* msg, UserPtr user);


  /** helper functions **/
  void start_resume_transfer_from(string key, uint64_t position, bool if_on_hold);
  void sendfile(FilePtr file);
  string construct_incoming_path(FilePtr file);

  string create_unique_key(string suggestion);
  bool add_file(FileMap& database, FilePtr file);
  FilePtr get_file(FileMap& database, string key);
  // FIXME: siehe open_file
//  FilePtr get_file(std::list<FilePtr>& database, string key);
  void remove_file(FileMap& database, FilePtr file);

  void status_map(ptree &pt, FileMap &database);
  void status_list(ptree &pt, FileList &database);
  void pause_db(FileMap &database);
  void hold_in_db(FileMap &database, UserPtr user);

  void save_database(FileMap &database, ptree &pt);
  void load_database(FileMap &database, ptree &pt);

private:
  Useroutputinterface* ui;
  Userdatabase* users;
  Transport* trans;

  FileMap incoming_transfers;
  FileMap outgoing_transfers;
  std::list<FilePtr> finished_transfers;
  FilePtr not_found;

  TransferBundleMap transfer_bundles;


  static const int BUFFSIZE = 2048; //XXX deprecated (in FileInfo)
  int unacked_pkg;
};

#endif /* FILETRANSFER_H_ */
